package com.code.monitor.utils;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Properties;

/**
 * @author ggh
 * @date 2023/5/8
 */
public class SSHUtils {
    //默认远程连接的端口
    private static Integer defaultSSHPort = 22;
    //默认远程window主机的字符集
    private static String defaultRemoteWindowCharset = "gbk";

    private static Logger logger = LoggerFactory.getLogger(SSHUtils.class);

    private static final String sftpRootPath = "C:\\tmp\\";

    private static final String baseCmd = "cmd /c ";

    private static final String startScriptPath = "start.bat %s %s";

    private static final String stopScriptPath = "stop.bat %s";

    /**
     * 执行远程服务器的命令
     *
     * @param hostIp
     * @param username
     * @param password
     * @param cmd
     * @param port
     */
    public static boolean execRemoteServiceOnWindows(String hostIp, Integer port, String username, String password, String cmd, String charset, String targetStr) {
        Session sshSession = null;
        try {
            logger.info("运行远程主机的服务，host:{},username:{}, password:{}, cmd:{}, charset:{}, targetStr:{}", hostIp, username, password, cmd, charset, targetStr);
            if (port == null || port == 0) {
                port = defaultSSHPort;
            }
            JSch jsch = new JSch();
            sshSession = jsch.getSession(username, hostIp, port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();

            ChannelExec channelExec = (ChannelExec) sshSession.openChannel("exec");
            channelExec.setCommand(cmd.getBytes(Charset.forName(defaultRemoteWindowCharset)));
            channelExec.setInputStream(null);
            channelExec.connect();

            if (StringUtils.isEmpty(charset)) {
                charset = defaultRemoteWindowCharset;
            }
            String result = null;
            String error = null;

            InputStream output = channelExec.getInputStream();
            InputStream errorOutput = channelExec.getErrStream();
            while (true) {
                if (output.available() > 0) {
                    result = IOUtils.readInputStream(output, Charset.forName(charset));
                    break;
                }
                if (errorOutput.available() > 0) {
                    error = IOUtils.readInputStream(errorOutput, Charset.forName(charset));
                    break;
                }
            }

            logger.info("cmd:{}运行结果:{}", cmd, result);
            if (!StringUtils.isEmpty(error)) {
                return false;
            }
            if (StringUtils.isEmpty(targetStr)) {
                return true;
            } else {
                return result == null ? false : result.contains(targetStr);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sshSession.disconnect();
        }
        return false;
    }

    /**
     * 启动jar包
     *
     * @param hostIp
     * @param username
     * @param password
     */
    public static boolean startRemoteServiceOnWindows(String hostIp, Integer port, String username, String password, String sftpRoot, String filePath, String fileName) {
        try {
            //1.拷贝jar文件
            scpFile(hostIp, port, username, password, filePath, "/");
            InputStream startUpStream = new ClassPathResource("bin/start.bat").getInputStream();

            //2.拷贝启动脚本
            scpFileByInputStream(hostIp, port, username, password, startUpStream, "/start.bat");
            return execRemoteServiceOnWindows(hostIp, port == null ? defaultSSHPort : port, username, password, String.format(baseCmd + sftpRoot + "/" + startScriptPath, hostIp, fileName), defaultRemoteWindowCharset, "success");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 停止jar包
     *
     * @param hostIp
     * @param username
     * @param password
     */
    public static boolean stopRemoteServiceOnWindows(String hostIp, Integer port, String username, String password, String sftpRoot, Integer servicePort) {
        try {
            InputStream stopStream = new ClassPathResource("bin/stop.bat").getInputStream();
            //拷贝停止脚本
            scpFileByInputStream(hostIp, port, username, password, stopStream, "/stop.bat");
            return execRemoteServiceOnWindows(hostIp, port == null ? defaultSSHPort : port, username, password, String.format(baseCmd + sftpRoot + "/" + stopScriptPath, servicePort), defaultRemoteWindowCharset, "success");
        } catch (
                Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 上传文件到sftp
     *
     * @param hostIp
     * @param username
     * @param password
     * @param port
     */
    public static boolean scpFile(String hostIp, Integer port, String username, String password, String file, String targetPath) {
        Session sshSession = null;
        try {
            logger.info("复制文件到远程主机，host:{},username:{}, password:{}, file:{}", hostIp, username, password, file);
            if (port == null || port == 0) {
                port = defaultSSHPort;
            }
            JSch jsch = new JSch();
            sshSession = jsch.getSession(username, hostIp, port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();

            ChannelSftp channelSftp = (ChannelSftp) sshSession.openChannel("sftp");
            channelSftp.connect();
            channelSftp.put(file, targetPath);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sshSession.disconnect();
        }
        return false;
    }

    /**
     * 上传文件到sftp
     *
     * @param hostIp
     * @param username
     * @param password
     * @param port
     */
    public static boolean scpFileByInputStream(String hostIp, Integer port, String username, String password, InputStream is, String targetPath) {
        Session sshSession = null;
        try {
            logger.info("复制文件到远程主机，host:{},username:{}, password:{}, file:{}", hostIp, username, password);
            if (port == null || port == 0) {
                port = defaultSSHPort;
            }
            JSch jsch = new JSch();
            sshSession = jsch.getSession(username, hostIp, port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();

            ChannelSftp channelSftp = (ChannelSftp) sshSession.openChannel("sftp");
            channelSftp.connect();
            OutputStream os = channelSftp.put(targetPath);

            int n = 0;
            byte[] bus = new byte[1024];
            while ((n = is.read(bus)) != -1) {
                os.write(bus, 0, n);
            }
            os.close();
            is.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sshSession.disconnect();
        }
        return false;
    }

    public static void main(String[] args) {
        String cmd = "cmd /c start AutoTestTool.exe \"C:\\autotest\\script\\scaffolding-test\\testfiles\\1内置自动布置\\MJ/MJ.pjs\" /run";

        System.out.println(execRemoteServiceOnWindows("192.168.1.143", 22, "yjkssh", "yjktest", cmd, null, null));
    }
}
